package epibot.WebRobots;

/**
 * Search in the SVMHC site. This site uses method POST
 *
 * http://abi.inf.uni-tuebingen.de/Services/SVMHC/
 */
import epibot.EstruturasBiologicas.Epitopo;
import epibot.EstruturasBiologicas.Proteina;
import epibot.robot.Proxy.GereciadorDoProxy;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

public class SVMHC {

    public static Proteina processCalibragem(String seq, String allele, String epi_len,
            String codProteina, String nomeSite) throws IOException {
        String rline; // Represents a line of the result table
        int line_count = 1;


        Proteina p = new Proteina(codProteina, nomeSite, allele, epi_len, 0); // só para armazenar a proteina e os epítopos



        // build the URL and POST
        URL url = new URL("http://abi.inf.uni-tuebingen.de/Services/SVMHC/svmhc2");

        //URLConnection http = url.openConnection();
        URLConnection http;
        Proxy proxy = GereciadorDoProxy.getConexao();

        if (proxy == null) {
            // System.out.println("sem proxy");
            http = url.openConnection();
        } else {
            // System.out.println("com proxy");
            http = url.openConnection(proxy);
        }
        http.setDoOutput(true);

        // OutputStream os = http.getOutputStream();
        OutputStream os = null;
        try {
            os = http.getOutputStream();
        } catch (UnknownHostException ex) {
            // System.out.println("proxy errado");
            return null;
        }

        // construct the form
        FormUtility form = new FormUtility(os, null);
        form.add("MHCPEP", "None");
        //faz a consulta por esse motor de busca
        form.add("SYFPEITHI", allele + (epi_len.equals("9") ? " nonamer" : " octamer"));
        form.add("CLASSII", "None");
        form.add("predict_seq", seq);
        form.add("db_id", "");
        form.add("mutation", "");

        // Submit form
        form.complete();

        // Read the results and parse the page
        InputStream is = http.getInputStream();
        ParseHTML parse = new ParseHTML(is);
        StringBuilder buffer = new StringBuilder();
        List<String> list = new ArrayList<String>();
        boolean capture = false;

        /**
         * SVHM responds with an intermediary page. So we first have to parse
         * this page to extract the link for the page with the result table.
         * Then, we access such page and in order to parse the result table.
         */
        // Go to the correct link in the intermediary result page
        if (!advance(parse, "/a", 5)) {
            return null;
        }

        // Parse the page to extract the link to the result table page
        int ch;
        String value = "";
        HTMLTag tag;
        while ((ch = parse.read()) != -1) {
            //System.out.print((char) ch);
            if (ch == 0) {
                tag = parse.getTag();
                if (tag.getName().equalsIgnoreCase("a")) {
                    value = tag.getAttributeValue("href");
                    break;
                }
            } else {
                buffer.append((char) ch);
            }
        }

        /*
         * Now access the final result page
         */
        URL url2 = new URL(value.toString());

        //System.out.println(url2.toString());

        URLConnection http2;
        if (proxy == null) {
            // System.out.println("sem proxy");
            http2 = url2.openConnection();
        } else {
            // System.out.println("com proxy");
            http2 = url2.openConnection(proxy);
        }
        //URLConnection http2 = url2.openConnection();
        InputStream is2 = http2.getInputStream();
        ParseHTML parse2 = new ParseHTML(is2);
        StringBuilder buffer2 = new StringBuilder();
        List<String> list2 = new ArrayList<String>();
        capture = false;

        // Go to the first line in the epitop table
        if (!advance(parse2, "table", 2)) {
            return null;
        }

        int rank = 0;
        String scoreAnt = "";

        // Parse the result page to get the result table
        while ((ch = parse2.read()) != -1) {
            //System.out.print((char)ch);
            if (ch == 0) {
                tag = parse2.getTag();
                if (tag.getName().equalsIgnoreCase("tr")) {
                    list2.clear();
                    capture = false;
                    buffer2.setLength(0);
                } else if (tag.getName().equalsIgnoreCase("/tr")) {
                    // Discard the initial table lines
                    if (line_count > 1) {
                        /*
                         * Write each found epitop to the result file
                         */
                        if (list2.size() > 0) {
                            rline = processTableRow(list2); // Extract the epitop from table line
                            rline = removeSpaces(rline);
                            //System.out.println(rline);
                            // Reorder the protein and the position in the string
                            int i, j;
                            i = rline.indexOf(',');
                            j = rline.lastIndexOf(',');

                            String epitopo = rline.substring(i + 1, j);
                            String posicao = rline.substring(0, i);
                            String score = rline.substring(j + 1);
                            //System.out.println(epitopo + "," + posicao + "," + score);


                            if (!score.equals(scoreAnt)) {
                                rank++;
                            }
                            scoreAnt = score;


                            p.addEpitopo(new Epitopo(epitopo, Integer.parseInt(posicao), Double.parseDouble(score), rank, p));

                        }
                        list2.clear();
                    }
                    line_count++;
                } else if (tag.getName().equalsIgnoreCase("td")) {
                    if (buffer2.length() > 0) {
                        list2.add(buffer2.toString());
                    }
                    buffer2.setLength(0);
                    capture = true;
                } else if (tag.getName().equalsIgnoreCase("/td")) {
                    list2.add(buffer2.toString());
                    buffer2.setLength(0);
                    capture = false;
                } else if (tag.getName().equalsIgnoreCase("/table")) {
                    break;
                }
            } else {
                if (capture) {
                    buffer2.append((char) ch);
                }
            }
        }
        is.close();
        is2.close();
        return p;
    }// fim do metodo process

    /**
     * Remove os espaços da string
     *
     * @param s String
     * @return
     */
    private static String removeSpaces(String s) {
        StringTokenizer st = new StringTokenizer(s, " ", false);
        String t = "";
        while (st.hasMoreElements()) {
            t += st.nextElement();
        }
        return t;
    }

    /**
     * Avancça para a tag HTML especificado.
     *
     * @param parse o objeto de análise HTML para usar.
     * @param tag A tag HTML.
     * @param count quantas etiquetas como esta para encontrar.
     *
     * @return True se encontrou, false caso contrário.
     * @throws IOException Se ocorrer uma exceção durante a leitura.
     */
    private static boolean advance(ParseHTML parse, String tag, int count) throws IOException {
        int ch;
        while ((ch = parse.read()) != -1) {
            if (ch == 0) {
                if (parse.getTag().getName().equalsIgnoreCase(tag)) {
                    count--;
                    if (count <= 0) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * Este método é chamado uma vez para cada linha da tabela localizado, ele
     * contém uma lista De todas as colunas dessa linha.
     *
     * @param list lista que foram encontrados nesta linha.
     *
     */
    private static String processTableRow(List<String> list) {
        int column_count = 1;
        StringBuilder result = new StringBuilder();

        for (String item : list) {
            // Determine the first column
            if (column_count > 0) {
                if (result.length() > 0) {
                    result.append(",");
                }
                result.append(item.trim());
            }
            column_count++;
        }
        return result.toString();
    }
}
